home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / Libraries / Sherlock 2.0 / DevLibSrc / Main_DevLib / LIBcmnd.c next >
Text File  |  1996-04-04  |  5KB  |  291 lines

  1. /*
  2.     devlib: command line routines.
  3.  
  4.     Do not put Sherlock macros in this file.
  5.  
  6.     source:  cmndline.c
  7.     started: November 4, 1993.
  8.     version:
  9.         September 25, 1995.
  10.             Use on_str and off_str in init_args.
  11.         January 9, 1994.
  12.             Abort if the argument file can not be found.
  13. */
  14.  
  15. #include <LIBlib.h>
  16. #include <LIBcmnd.h>
  17. #include <LIBend.h>
  18. #include <LIBmem.h>
  19.  
  20. #include <stdio.h>
  21. #include <stdlib.h>
  22.  
  23. #define arg_is_ws(c) ((c)==' ' || (c)=='\t' || (c)=='\n' || (c)=='\r')
  24.  
  25. static void        init_massage    (register char * s);
  26. static char *    init_skip_arg    (register char * p);
  27. static char *    init_skip_ws    (register char * p);
  28. static void        init_err        (char *message, char *file_name);
  29.  
  30. /*
  31.     Initialize the argv vector from a file.
  32. */
  33. void
  34. init_args(int * argc, char *** argvp, char * name)
  35. {
  36.     long size, read_size;
  37.     char * buffer;
  38.  
  39.     FILE * init_arg_file = fopen(name, "r");
  40.  
  41.     if (init_arg_file == NULL) {
  42.         *argc = 1;
  43.         init_err("Can not open", name);
  44.         end_usage();
  45.     }
  46.  
  47.     /* Find out how big the file is by seeking to the end. */
  48.     if (fseek(init_arg_file, 0L, SEEK_END) != 0) {
  49.         *argc = 1;
  50.         init_err("Can not seek on", name);
  51.         return;
  52.     }
  53.     size = ftell(init_arg_file);
  54.  
  55.     /* Reposition the file at the start. */
  56.     if (fseek(init_arg_file, 0L, SEEK_SET) != 0) {
  57.         *argc = 1;
  58.         init_err("Can not re-seek on", name);
  59.         return;
  60.     }
  61.  
  62.     /* Allocate a buffer big enough to hold the whole file. */
  63.     buffer = lib_calloc( (size_t) 1, size+10);
  64.     if (buffer == NULL) {
  65.         *argc = 1;
  66.         init_err("Can not allocate buffer for", name);
  67.         return;
  68.     }
  69.  
  70.     /* Read the whole file into the buffer. */
  71.     read_size = fread(buffer, 1, size, init_arg_file);
  72.     buffer[read_size] = '\0';
  73.  
  74.     /* Create the arguments. */
  75.     init_massage(buffer);
  76.     *argc = init_arg_parse(argvp, buffer);
  77. }
  78.  
  79. /*
  80.     Print a file error message.
  81. */
  82. static void
  83. init_err(char *message, char *name)
  84. {
  85.     es(message); eblank(); es(name); enl();
  86. }
  87.  
  88. /*
  89.     Eliminate comments that start with ! and go to the end of the line.
  90.     Either '\n' or '\r' end lines and both are converted to blanks.
  91. */
  92. static void
  93. init_massage(register char * s)
  94. {
  95.     register char * s2 = s;
  96.     char delim;
  97.     char * line_start = s;
  98.  
  99.     /*
  100.         Do not put Sherlock macros here: Sherlock has not been initialized!
  101.     */
  102.  
  103.     /* Bug fix:  9/14/91 */
  104.     if (s == NULL) {
  105.         return;
  106.     }
  107.  
  108.     for(;;) {
  109.         switch (*s) {
  110.  
  111.         case '\0':
  112.  
  113.             /* Finish off the string. */
  114.             *s2 = '\0';
  115.             return;
  116.  
  117.         case '\'':
  118.         case '"':
  119.         case '`':
  120.         {
  121.             /* Copy strings */
  122.             delim = *s;
  123.             *s2++ = *s++;
  124.             while (*s != delim) {
  125.                 if (*s == '\n' || *s == '\r' || *s == '\0') {
  126.                     *s = '\0';
  127.                     init_err("Run on string in argument list:", line_start);
  128.                     end_usage();
  129.                 }
  130.                 *s2++ = *s++;
  131.             }
  132.             *s2++ = *s++;
  133.             break;
  134.         }
  135.  
  136.         case '!':
  137.  
  138.             /* Skip comments. */
  139.             while(*s && *s != '\n' && *s != '\r') {
  140.                 s++;
  141.             }
  142.             break;
  143.  
  144.         case '\r':
  145.         case '\n':
  146.  
  147.             /* Convert end of line characters to blanks. */
  148.             *s2++ = ' ';
  149.             s++;
  150.             line_start = s;
  151.             break;
  152.  
  153.         default:
  154.             /* Copy all other characters. */
  155.             *s2++ = *s++;
  156.         }
  157.     }
  158. }
  159.  
  160. /*
  161.     Convert the string in buf into a list of pointers to the elements.
  162.     Set *argvp pointing to the newly created list.
  163.  
  164.     On exit, argc is:
  165.  
  166.     1.  One LESS than the total number of elements in the argv vector,
  167.         counting the NULL element at the end.
  168.     2.  The number of arguments in the argv vector, counting the zeroth
  169.         argument, but not counting the NULL element at the end.
  170.     3.  One MORE than the number of user arguments, not counting the
  171.         zeroth argument.
  172. */
  173. int
  174. init_arg_parse(char *** argvp, register char * buf)
  175. {
  176.     register int        argc;
  177.     register char **    argv;
  178.     register int        i;
  179.     register char *        p;
  180.     static char *        ftag = "init_arg_parse";
  181.  
  182.     /*
  183.         Do not put Sherlock macros here: Sherlock has not been initialized!
  184.     */
  185.  
  186.     /* Bug fix:  9/14/91 */
  187.     if (buf == NULL) {
  188.         return 0;
  189.     }
  190.  
  191.     /* Find out how many entries argv will contain. */
  192.     for (p = buf, argc = 0; ;) {
  193.         p = init_skip_ws(p);
  194.         if (!*p) { break; }
  195.         argc++;
  196.         p = init_skip_arg(p);
  197.     }
  198.     if (argc == 0) { return argc; }
  199.  
  200.     /* Allocate space for the array. */
  201.     argv = (char **) lib_calloc ( (size_t) 1, (argc+2)*sizeof(char *));
  202.     *argvp = argv;
  203.  
  204.     /* Set up the argv array. */
  205.     for (p = buf, i = 0; ;) {
  206.  
  207.         p = init_skip_ws(p);
  208.         if (!*p) { break; }
  209.  
  210.         if (*p == '"' || *p == '\'' || *p == '`') {
  211.             argv[i++] = p+1;
  212.         }
  213.         else {
  214.             argv[i++] = p;
  215.         }
  216.         p = init_skip_arg(p);
  217.  
  218.         /* Step back over the delimiter, so it will be replaced by '\0' */
  219.         if (*(p-1) == '"' || *(p-1) == '\'' || *(p-1) == '`') {
  220.             p--;
  221.         }
  222.  
  223.         /* End the argument. */
  224.         if (!*p) {
  225.             break;
  226.         }
  227.         else {
  228.             *p++ = '\0';
  229.         }
  230.     }
  231.  
  232.     /* Put a trailing null argument. */
  233.     argv[i] = NULL;
  234.  
  235.     return argc;
  236. }
  237.  
  238. /*
  239.     Skip over an argument.
  240.  
  241.     Allow string arguments containing white space and backslash double quotes.
  242. */
  243. static char *
  244. init_skip_arg(register char * p)
  245. {
  246.     char * start_p = p;
  247.     char delim;
  248.  
  249.     if (*p == '"' || *p == '\'' || *p == '`') {
  250.  
  251.         /* Skip the beginning quote. */
  252.         delim = *p++;
  253.  
  254.         /* Skip until end of string */
  255.         for(;;) {
  256.             if (!*p) {
  257.                 init_err("Unterminated argument string: ", start_p);
  258.                 end_usage();
  259.             }
  260.             else if (*p == '\\' && *(p+1) == delim) {
  261.                 p += 2;
  262.             }
  263.             else if (*p == delim) {
  264.                 p++;
  265.                 break;
  266.             }
  267.             else {
  268.                 p++;
  269.             }
  270.         }
  271.     } else {
  272.         /* Skip until non white space */
  273.         while(*p && !arg_is_ws(*p)) {
  274.             p++;
  275.         }
  276.     }
  277.     return p;
  278. }
  279.  
  280. /*
  281.     Skip over white space.
  282. */
  283. static char *
  284. init_skip_ws(register char * p)
  285. {
  286.     while(arg_is_ws(*p)) {
  287.         p++;
  288.     }
  289.     return p;
  290. }
  291.